package proxy;

/**
 * 模拟Java动态代理机制
 */

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 模拟JAVA动态代理类
 * 
 * 
 * JAVA原生动态代理类由ProxyGenerator动态生成实现代理接口的字节码，并注入classloader中。 参见源码： String
 * proxyName = proxyPkg + "$proxy" + num; byte[] proxyClassFile =
 * ProxyGenerator.generateProxyClass(proxyName, interfaces); proxyClass =
 * defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
 * 
 * 代理机制： 代理类和委托代理类都实现了代理接口，当代理类调用代理接口时，首先会触发调用处理程序。
 * 再由处理程序分发调用委托代理类的接口。从而实现了代理类对委托代理类的隔离。
 * 
 * @author Andy
 * @see com.demo.delegator.IDelegator.One
 * @see com.demo.delegator.IDelegator.Two
 * @see com.demo.delegator.IDelegator.Three
 * @since 2012.02.17 15:59 PM
 * @version 1.0
 */
public final class DynamicProxy implements IDelegator.One, IDelegator.Two,
		IDelegator.Three {

	// 引用调用处理对象
	private static InvocationHandler handler;
	private static Class<?>[] interfaces = null;
	private static Map<Class<?>, DynamicProxy> cachMap = Collections
			.synchronizedMap(new HashMap<Class<?>, DynamicProxy>());

	private DynamicProxy(Class<?>[] interfaces, InvocationHandler handler) {
		DynamicProxy.handler = handler;
		DynamicProxy.interfaces = interfaces;
	}

	public static Object newInstance(Class<?> clazz, Class<?>[] interfaces,
			InvocationHandler handler) {
		DynamicProxy proxy = cachMap.get(clazz);
		if (null == proxy) {
			proxy = new DynamicProxy(interfaces, handler);
			cachMap.put(clazz, proxy);
		}
		return proxy;
	}

	@Override
	public String read() {
		return String.valueOf(this.invoke());
	}

	@Override
	public int write() {
		return Integer.valueOf(this.invoke().toString());
	}

	@Override
	public void sing() {
		this.invoke();
	}

	private Object invoke() {
		Object obj = null;
		try {
			StackTraceElement[] elements = Thread.currentThread()
					.getStackTrace();
			String methodName = elements[2].getMethodName();

			for (int i = 0; i < interfaces.length; i++) {
				Class<?> clazz = interfaces[i];
				Method[] methods = clazz.getMethods();
				for (int j = 0; j < methods.length; j++) {
					Method method = methods[j];
					if (methodName.equals(method.getName())) {
						Class<?> args[] = method.getParameterTypes();
						obj = handler.invoke(this, method, args);
						break;
					}
				}
			}

			return obj;
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

}
